package engine;

import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import render.Rasterizer;
import render.RenderEngine;
import tool.Timer;

public abstract class EngineBase extends Canvas {
    
    public final int viewportW;
    public final int viewportH;
    public final int pixelsW;
    public final int pixelsH;
    private int[] pixels;
    private boolean running;
    private BufferStrategy bs;
    private BufferedImage img;
    private Graphics g;
    private Rasterizer raster;
    private Timer timerSecond;
    private Point locationPrev;
    private Cursor cursorPrev;
    protected int framerate;
    protected float timeCycle;
    protected Timer timerCycle;
    protected RenderEngine renderEngine;
    protected Keys keys;
    protected Mouse mouse;
    
    public EngineBase(int windowW, int windowH, int drawingW, int drawingH) {
        super();
        viewportW = windowW;
        viewportH = windowH;
        pixelsW = drawingW;
        pixelsH = drawingH;
        Dimension size = new Dimension(viewportW, viewportH);
        this.setSize(size);
        this.setPreferredSize(size);
        this.setMinimumSize(size);
        this.setMaximumSize(size);
        this.setFocusable(true);
        img = new BufferedImage(pixelsW, pixelsH, BufferedImage.TYPE_INT_ARGB);
        pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
        running = true;
        raster = new Rasterizer(pixelsW, pixelsH, pixels);
        renderEngine = new RenderEngine(raster);
        timerCycle = new Timer(false);
        timerSecond = new Timer(false);
        keys = new Keys();
        mouse = new Mouse(viewportW, viewportH);
        this.addKeyListener(keys);
    }
    
    public void run() {
        this.loadImageFiles();
        mouse.setComponentPos(this.getLocationOnScreen());
        this.onStart();
        timerCycle.start();
        timerSecond.start();
        while (running) {
            framerate++;
            mouse.update();
            if (!this.getLocationOnScreen().equals(locationPrev)) {
                locationPrev = this.getLocationOnScreen();
                mouse.setComponentPos(locationPrev);
            }
            if (!mouse.getCursor().equals(cursorPrev)) {
                cursorPrev = mouse.getCursor();
                this.setCursor(cursorPrev);
            }
            if (keys.isDown(Keys.ESCAPE)) {
                running = false;
                return;
            }
            if (timerSecond.getTimePassed() >= 1.0f) {
                timerSecond.moveBackBy(1.0f);
                this.perSecond();
                framerate = 0;
            }
            timeCycle = timerCycle.stopAndReturnTime();
            timerCycle.start();
            this.update();
            this.render();
        }
        this.onClose();
    }
    
    private void render() {
        bs = this.getBufferStrategy();
        if (bs == null) {
            createBufferStrategy(3);
            return;
        }
        
        renderEngine.render();
        
        g = bs.getDrawGraphics();
        g.fillRect(0, 0, viewportW, viewportH);
        g.drawImage(img, 0, 0, viewportW, viewportH, null);
        g.dispose();
        bs.show();
    }
    
    protected void loadImageFiles() {
        
    }
    
    protected void onStart() {
        
    }
    
    protected void update() {
        
    }
    
    protected void perSecond() {
        
    }
    
    protected void onClose() {
        
    }
    
}
